/**
 * 代号:404NotFound  2018：上海
 * 文件名：MyShiroRealm.java
 * 创建人：袁豪
 * 日期：2018年8月31日 上午9:15:22
 */
package com.holystone.orca.itsm.shiro;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.holystone.orca.itsm.system.api.SystemServiceApi;
import com.holystone.orca.itsm.system.model.SysUser;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;

import java.util.HashSet;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 用途：业务模块名称
 */
public class MyShiroRealm extends AuthorizingRealm {

	// 用户登录次数计数 redisKey 前缀
	private String SHIRO_LOGIN_COUNT = "shiro_login_count_";

	// 用户登录是否被锁定 一小时 redisKey 前缀
	private String SHIRO_IS_LOCK = "shiro_is_lock_";

	@Autowired
	private StringRedisTemplate redisTemplate;

    @Reference(version = "${itsm.controller.version}",
            application = "${dubbo.application.id}",
            check = false,
            url = "dubbo://localhost:12345")
    private SystemServiceApi serviceApi;

	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		System.out.println("授权认证：MyShiroRealm.doGetAuthorizationInfo()");
		Object principal = principals.getPrimaryPrincipal();
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		// 曲线救国
		System.out.println(principal instanceof SysUser);
		SysUser user;
		if (principal instanceof SysUser) {
			user = (SysUser) principal;
		} else {
			String temp = JSON.toJSON(principal).toString();
			user = JSON.parseObject(temp, SysUser.class);
		}
		System.out.println("user数据：" + user.toString());
		List<String> roleList = serviceApi.selectUserRole(user.getUserId());

		info.setRoles(new HashSet<>(roleList));
		System.out.println("info=========" + info.getStringPermissions());
		return info;
	}

	// 认证信息.(身份验证) : Authentication 是用来验证用户身份
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken)
			throws AuthenticationException {

		System.out.println("身份验证doGetAuthenticationInfo");
		UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
		String username = token.getUsername();
		String password = String.valueOf(token.getPassword());
		// 每访问一次记录一次
		ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();
		if ("LOCKED".equals(opsForValue.get(SHIRO_IS_LOCK + username))) {
			throw new DisabledAccountException("由于密码输入错误次数大于5次，帐号30分钟内禁止登录！");
		}
		Long i = opsForValue.increment(SHIRO_LOGIN_COUNT + username, 1);
		System.out.println("登录统计次数===" + i);
		// 判断登录次数(大于5次则锁定用户)
		if (Integer.valueOf(opsForValue.get(SHIRO_LOGIN_COUNT + username)) > 1000) {
			redisTemplate.delete(SHIRO_LOGIN_COUNT + username);
			opsForValue.set(SHIRO_IS_LOCK + username, "LOCKED", 30, TimeUnit.MINUTES);
			throw new DisabledAccountException("由于密码输入错误次数大于5次，帐号30分钟内禁止登录！");
		}
		// 盐值
		ByteSource salt = ByteSource.Util.bytes(username);
		System.out.println("加密结果：" + username + "密码：" + password);
		SysUser user = serviceApi.login(username, password);
		if (user == null) {
			throw new AccountException("帐号或密码不正确！");
		} else if (String.valueOf(user.getState()).equals("0")) {
			throw new DisabledAccountException("账号已禁止登录，请稍后重试");
		} else {
			// 登录成功 清空错误次数
			redisTemplate.delete(SHIRO_IS_LOCK + username);
			redisTemplate.delete(SHIRO_LOGIN_COUNT + username);
		}

		SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, salt, getName());

		return info;
	}

}
